using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Linq;

namespace Acms.DataControls
{
    [ToolboxData("<{0}:AcmsSiteMapDataSource runat=server></{0}:AcmsSiteMapDataSource>")]
    public class AcmsSiteMapDataSource : HierarchicalDataSourceControl
    {
        public AcmsSiteMapDataSource()
        {
            CurrentSiteVersion = DateTime.Now;
        }

        public string MenuName{ get; set; }
        public string RootText{ get; set; }
        public string ParentPath { get; set; }
        public bool IncludeParent { get; set; }
        public bool FlattenParent { get; set; }
        public int SiteId { get; set; }
        public DateTime? CurrentSiteVersion { get; set; }
        public int MenuId{ get; private set; }
        public string CurrentRelativeUrl { get; set; }

        private void EnsureLoaded()
        {
            //if SiteId and Site Cersion have not been set then do so
            if (SiteId == 0)
            {
                var acmsPage = Page as Acms.AcmsControls.TemplatePage;
                if (acmsPage != null)
                {
                    SiteId = acmsPage.AcmsContext.SiteId;
                    CurrentSiteVersion = acmsPage.AcmsContext.SiteVersion;
                }
            }
            if (MenuId == 0 && !string.IsNullOrEmpty(MenuName))
            {
                Bll.Menu menu = Bll.Menu.GetByNameAndSiteId(MenuName, SiteId);
                if (menu != null)
                {
                    MenuId = menu.Id;
                    if (string.IsNullOrEmpty(ParentPath))
                    {
                        if (CurrentRelativeUrl != null)
                        {
                            ParentPath = menu.ConvertParentPath(CurrentRelativeUrl);
                        }
                        else
                        {
                            ParentPath = menu.ConvertParentPath(Page.Request.AppRelativeCurrentExecutionFilePath);
                        }
                        IncludeParent = menu.IncludeParent;
                    }
                }
            }
        }

        private HierarchicalDataSourceView view;
        protected override HierarchicalDataSourceView GetHierarchicalView(string viewPath)
        {
            if (view == null)
            {
                EnsureLoaded();
                view = new AcmsSiteMapDataSourceView(this);
            }
            return view;
        }

        internal List<Bll.Post> GetInitialForMenu(int menuId)
        {
            List<Bll.Post> retVal = null;
            if (!string.IsNullOrEmpty(ParentPath))
            {
                if (IncludeParent || FlattenParent)
                {
                    //get post by parent path
                    retVal = GetList(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                }
                else
                {
                    //get children by parent path
                    retVal = Bll.Post.GetAllBySiteIdMenuIdAndParentPath(SiteId, menuId, ParentPath, CurrentSiteVersion);
                }
            }
            else
            {
                if (IncludeParent || FlattenParent)
                {
                    //get top level
                    retVal = GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                }
                else
                {
                    //get children of home page
                    retVal = Bll.Post.GetAllBySiteIdMenuIdAndParentPath(SiteId, menuId, "~/", CurrentSiteVersion);
                }
            }

            //add in the children if flatten parent
            if (FlattenParent && retVal.Count == 1)
            {
                //get all children
                retVal.AddRange(Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, menuId, retVal.First().PostGuid, CurrentSiteVersion));
            }
            return retVal;
        }   

        internal List<Bll.Post> GetInitialWithoutMenu()
        {
            List<Bll.Post> retVal = null;
            if (!string.IsNullOrEmpty(ParentPath))
            {
                if (IncludeParent || FlattenParent)
                {
                    //get post by parentpath
                    retVal = GetList(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                }
                else
                {
                    //get children by parent path
                    retVal = Bll.Post.GetAllBySiteIdAndParentPath(SiteId, ParentPath, CurrentSiteVersion);
                }
            }
            else
            {
                if (IncludeParent || FlattenParent)
                {
                    //get top level
                    retVal = GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                }
                else
                {
                    //get children of home page
                    retVal = Bll.Post.GetAllBySiteIdAndParentPath(SiteId, "~/", CurrentSiteVersion);
                }
            }

            if (FlattenParent && retVal.Count == 1)
            {
                retVal.AddRange(Bll.Post.GetAllByParentGuid(SiteId, retVal.First().PostGuid, CurrentSiteVersion));
            }

            return retVal;
        }

        internal List<Bll.Post> GetInitial(bool ignoreRootText)
        {
            if (!ignoreRootText && !string.IsNullOrEmpty(RootText))
            {
                Bll.Post tmp = Bll.Post.CreateInstance();
                tmp.DisplayName = RootText;
                return GetList(tmp);
            }
            else if (MenuId != 0)
            {
                return GetInitialForMenu(MenuId);
/*                if (IncludeParent && !string.IsNullOrEmpty(ParentPath))
                {
                    Bll.Post tmp = Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion);
                    return GetList(tmp);
                }
                else if (FlattenParent && !string.IsNullOrEmpty(ParentPath))
                {
                    var tmp = new List<Bll.Post>();
                    tmp.Add(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                    if (tmp.Count == 1)
                    {
                        tmp.AddRange(Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, MenuId, tmp.First().PostGuid, CurrentSiteVersion));
                    }
                    return tmp;
                }
                else if (!string.IsNullOrEmpty(ParentPath))
                {
                    return Bll.Post.GetAllBySiteIdMenuIdAndParentPath(SiteId, MenuId, ParentPath, CurrentSiteVersion);
                }
                else if (FlattenParent)
                {
                    var tmp = new List<Bll.Post>();
                    tmp.Add(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                    if (tmp.Count == 1)
                    {
                        tmp.AddRange(Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, MenuId, tmp.First().PostGuid, CurrentSiteVersion));
                    }
                    return tmp;
                }
                else
                {
                    return GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                }*/
            }
            else
            {
                return GetInitialWithoutMenu();
            }
            /*else if (!string.IsNullOrEmpty(ParentPath))
            {
                if (IncludeParent)
                {
                    Bll.Post tmp = Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion);
                    return GetList(tmp);
                }
                else if (FlattenParent)
                {
                    var tmp = new List<Bll.Post>();
                    tmp.Add(Bll.Post.GetBySiteIdAndPath(SiteId, ParentPath, CurrentSiteVersion));
                    if (tmp.Count == 1)
                    {
                        tmp.AddRange(Bll.Post.GetAllByParentGuid(SiteId, tmp.First().PostGuid, CurrentSiteVersion));
                    }
                    return tmp;
                }
                else
                {
                    return Bll.Post.GetAllBySiteIdAndParentPath(SiteId, ParentPath, CurrentSiteVersion);
                }
            }
            else if (IncludeParent)
            {
                return GetList(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
            }
            else if (FlattenParent)
            {
                var tmp = new List<Bll.Post>();
                tmp.Add(Bll.Post.GetTopLevelBySiteId(SiteId, CurrentSiteVersion));
                if (tmp.Count == 1)
                {
                    tmp.AddRange(Bll.Post.GetAllByParentGuid(SiteId, tmp.First().PostGuid, CurrentSiteVersion));
                }
                return tmp;
            }
            else
            {
                return Bll.Post.GetAllBySiteIdAndParentPath(SiteId, "~/", CurrentSiteVersion);
            }*/
        }

        private bool IsParent(Bll.Post post)
        {
            if (post != null)
            {
                if (post.ParentPath == null)
                {
                    return true;
                }
                else if (post.Path == this.ParentPath || string.Concat(post.Path, "/") == this.ParentPath || post.Path == string.Concat(this.ParentPath, "/"))
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
            else
            {
                return false;
            }
        }

        internal List<Bll.Post> GetChildren(Bll.Post post)
        {
            if (post == null || post.Id == 0)
            {
                return GetInitial(true);
            }
            else if (FlattenParent && IsParent(post))
            {
                return null;
            }
            else if (MenuId != 0)
            {
                return Bll.Post.GetAllByMenuIdAndParentGuid(SiteId, MenuId, post.PostGuid, CurrentSiteVersion);
            }
            else
            {
                return Bll.Post.GetAllByParentGuid(SiteId, post.PostGuid, CurrentSiteVersion);
            }
        }

        private List<Bll.Post> GetList(Bll.Post post)
        {
            List<Bll.Post> tmp = new List<Acms.Bll.Post>();
            if(post != null)
                tmp.Add(post);
            return tmp;
        }

        protected override object SaveViewState()
        {
            ViewState["SiteId"] = SiteId;
            ViewState["MenuName"] = MenuName;
            ViewState["MenuId"] = MenuId;
            ViewState["ParentPath"] = ParentPath;
            ViewState["RootText"] = RootText;
            ViewState["CurrentSiteVersion"] = CurrentSiteVersion;
            ViewState["CurrentRelativeUrl"] = CurrentRelativeUrl;
            return base.SaveViewState();
        }

        protected override void LoadViewState(object savedState)
        {
            base.LoadViewState(savedState);
            if (ViewState["SiteId"] is int)
                SiteId = (int)ViewState["SiteId"];
            MenuName = ViewState["MenuName"] as string;
            if (ViewState["MenuId"] is int)
                MenuId = (int)ViewState["MenuId"];
            ParentPath = ViewState["ParentPath"] as string;
            RootText = ViewState["RootText"] as string;
            CurrentSiteVersion = ViewState["CurrentSiteVersion"] as DateTime?;
            CurrentRelativeUrl = ViewState["CurrentRelativeUrl"] as string;
        }
    }

    public class AcmsSiteMapDataSourceView : HierarchicalDataSourceView
    {
        public AcmsSiteMapDataSourceView(AcmsSiteMapDataSource owner) : base() { this.owner = owner; }

        AcmsSiteMapDataSource owner;

        public override IHierarchicalEnumerable Select()
        {
            return new AcmsSiteMapEnumerator(owner.GetInitial(false), owner);
        }
    }

    public class AcmsSiteMapEnumerator : IHierarchicalEnumerable
    {
        public AcmsSiteMapEnumerator(Bll.Post post, AcmsSiteMapDataSource owner)
        {
            this.posts = new List<Acms.Bll.Post>();
            posts.Add(post);
            this.owner = owner;
        }

        public AcmsSiteMapEnumerator(List<Bll.Post> posts, AcmsSiteMapDataSource owner)
        {
            this.posts = posts;
            this.owner = owner;
        }

        AcmsSiteMapDataSource owner;
        #region IHierarchicalEnumerable Members

        public IHierarchyData GetHierarchyData(object enumeratedItem)
        {
            return new AcmsSiteMapData(enumeratedItem as Bll.Post, owner);
        }

        #endregion

        #region IEnumerable Members

        private List<Bll.Post> posts = null;

        public System.Collections.IEnumerator GetEnumerator()
        {
            if (posts != null)
            {
                foreach (Bll.Post p in posts)
                {
                    yield return p;
                }
            }
        }

        #endregion
    }

    public class AcmsSiteMapData : IHierarchyData
    {
        public AcmsSiteMapData(Bll.Post post, AcmsSiteMapDataSource owner)
        {
            this.post = post;
            this.owner = owner;
        }

        AcmsSiteMapDataSource owner;

        private Bll.Post post;

        private List<Bll.Post> children;
        protected List<Bll.Post> Children
        {
            get 
            {
                if (children == null)
                {
                    children = owner.GetChildren(post);
                }
                return children;
            }

        }

        #region IHierarchyData Members

        public IHierarchicalEnumerable GetChildren()
        {
           return new AcmsSiteMapEnumerator(Children, owner);
        }

        public IHierarchyData GetParent()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        public bool HasChildren
        {
            get { return Children != null && Children.Count > 0; }
        }

        public object Item
        {
            get 
            {
                return post;
            }
        }

        public string Path
        {
            get
            {
                if (post != null)
                {
                    return post.Path;
                }
                else
                {
                    return null;
                }
            }
        }

        public string Type
        {
            get
            {
                if (post != null)
                {
                    return post.GetType().ToString();
                }
                else
                {
                    return null;
                }
            }
        }

        #endregion
    }
}   
